<template>
    <van-sticky>
        <van-nav-bar :title="title" left-text="返回" left-arrow @click-left="onClickLeft">
            <template #right>
                <span class="dots-menu" @click.stop="showActionSheet = true">⋯</span>
            </template>
        </van-nav-bar>
        <div v-if="cxhtCacheData != null">
            <van-action-sheet v-model:show="showActionSheet" :actions="actionSheetActions"
                @select="onActionSheetSelect" />
            <van-search v-model="searchQuery" placeholder="请输入搜索关键词" />
            <div class="progress-container">
                <van-progress :percentage="progressPercentage" color="#409EFF" />
            </div>
        </div>
    </van-sticky>
    <van-popup v-model:show="showCascaderPopup" position="bottom" style="width: 100%;" :close-on-click-overlay="false">
        <div>
            <van-loading v-if="cascaderLoading" color="#409EFF" size="30" class="loading-container" />
            <van-cascader v-model="cascaderValue" :options="cascaderOptions" :depth="4" title="请选择今日工作设备"
                @finish="onCascaderFinish" @change="onCascaderChange" @cancel="showCascaderPopup = false"
                :loading="cascaderLoading" @close="closeCascaderPopup()" />
        </div>
    </van-popup>
    <van-collapse v-model="activeNames" accordion>
        <van-collapse-item v-for="(keyGroup, key) in filteredKeyGroups" :key="key" :name="key">
            <template #title>
                <div class="collapse-title">
                    <span>{{ key }}</span>
                    <span class="progress-text" :class="getProgressClass(keyGroup)">
                        {{ getProgressText(keyGroup) }}
                    </span>
                </div>
            </template>
            <van-button v-for="(item, itemIndex) in keyGroup" :key="itemIndex" block class="collapse-item-button"
                :class="{
                    'correct-btn': item.isRight === 1,
                    'incorrect-btn': item.isRight === -1
                }" @click="buttonClick(item, key)">
                {{ item.cxhtFormItem.startNumber }} → {{ item.cxhtFormItem.endPart }} : {{
                    item.cxhtFormItem.endNumber
                }}
            </van-button>
        </van-collapse-item>
    </van-collapse>
    <van-popup v-model:show="showPopup" round :style="{ padding: '0' }" position="center">
        <div class="dialog-content">
            <div class="circuit-name">
                {{ itemData.cxhtFormItem.loop }}
            </div>
            <div class="startend-text">
                {{ itemData.cxhtFormItem.startNumber }} → {{ itemData.cxhtFormItem.endPart }} : {{
                    itemData.cxhtFormItem.endNumber }}
            </div>
            <van-button type="success" @click="setResult(1)" style="height: 100px;">正常</van-button>
            <van-button type="danger" @click="setResult(-1)">错误</van-button>
            <van-field v-model="itemData.remark" placeholder="输入备注" type="text" border
                :style="{ width: '100%', marginTop: '16px' }" @change="handleRemarkChange" />
        </div>
    </van-popup>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue';
import { naturalSort } from '@/utils/NaturalSort';
import { showConfirmDialog, showToast, showLoadingToast, closeToast, showFailToast, showSuccessToast } from 'vant';
import formAPI from "@/api/cxht.js";
import optionAPI from "@/api/options.js";
import db from "@/utils/Dexie.js";
import { errorNotify } from "@/utils/Misc";
import { useRouter } from 'vue-router';
const router = useRouter();
const cxhtCacheKey = ref(new URLSearchParams(window.location.search).get("key") || "查线核图");
const title = ref("查线核图");
const showCascaderPopup = ref(true);
const cascaderValue = ref("");
const cascaderOptions = ref([]);
const searchQuery = ref('');
const currentKey = ref('');
const onClickLeft = () => history.back();
const activeNames = ref("");
const showPopup = ref(false);
const itemData = ref(null);
const cxhtCacheData = ref(null);
const showActionSheet = ref(false);
const cascaderLoading = ref(false);
onMounted(() => {
    initCascaderOptions();
});
const initCascaderOptions = async () => {
    if (navigator.onLine) {
        cascaderOptions.value = [
            {
                text: '四号线',
                value: '620a7464-5238-4b88-a3ed-a1fa34d2e2a1',
                children: []
            },
            {
                text: '六号线',
                value: '367ccf6f-7379-4f17-986f-8c3539b7268b',
                children: []
            }
        ];
    } else {
        cascaderOptions.value = [];
        const nodesMap = {
            level1: new Map(),
            level2: new Map(),
            level3: new Map(),
            level4: new Map()
        };
        try {
            const data = await db.cxhtCache.toArray();
            const addNode = (parentNodes, nodeKey, nodeValue, map, parentKey = '') => {
                const key = parentKey ? `${parentKey}_${nodeValue}` : nodeValue;
                if (map.has(key)) {
                    return map.get(key);
                }
                const newNode = {
                    text: nodeValue,
                    value: nodeValue,
                    children: []
                };
                parentNodes.push(newNode);
                map.set(key, newNode);
                return newNode;
            };
            data.forEach(item => {
                const key = item.key;
                const keys = key.split('_');
                if (keys.length === 4) {
                    const [level1, level2, level3, level4] = keys;
                    const level1Node = addNode(
                        cascaderOptions.value,
                        'level1',
                        level1,
                        nodesMap.level1
                    );
                    const level2Node = addNode(
                        level1Node.children,
                        'level2',
                        level2,
                        nodesMap.level2,
                        level1
                    )
                    const level3Node = addNode(
                        level2Node.children,
                        'level3',
                        level3,
                        nodesMap.level3,
                        `${level1}_${level2}`
                    );
                    const level4Key = `${level1}_${level2}_${level3}_${level4}`;
                    if (!nodesMap.level4.has(level4Key)) {
                        const level4Node = {
                            text: level4,
                            value: level4
                        };
                        level3Node.children.push(level4Node);
                        nodesMap.level4.set(level4Key, level4Node);
                    }
                }
            });
        } catch (error) {
            errorNotify("ChaXianHeTu.vue", "initCascaderOptions", error);
        }
    }
};
const onCascaderChange = (data) => {
    if (data.tabIndex == 0) {
        getSubstation(data.value)
    } else if (data.tabIndex == 1) {
        getEquipment(data.value)
    }
};
const closeCascaderPopup = () => {
    router.back()
}
const getSubstation = (id) => {
    const existingItem = cascaderOptions.value.find(item => item.value === id);
    if (existingItem && existingItem.children && existingItem.children.length > 0) {
        return;
    }
    cascaderLoading.value = true;
    optionAPI.getSubstation(id).then(res => {
        cascaderOptions.value.forEach(item => {
            if (item.value === id) {
                item.children = res.data.tree.locationTree.map(child => ({
                    text: child.name,
                    value: child.id,
                    children: []
                })).sort((a, b) => a.text.localeCompare(b.text, undefined, {
                    numeric: true,
                    sensitivity: 'base'
                }));
            }
        });
        cascaderLoading.value = false;
    }).catch(error => {
        errorNotify("ChaXianHeTu.vue", "getSubstation", error);
        cascaderLoading.value = false;
    });
}
const getEquipment = (stationId) => {
    const lineItem = cascaderOptions.value.find(line =>
        line.children && line.children.some(station => station.value === stationId)
    );
    const stationItem = lineItem
        ? lineItem.children.find(station => station.value === stationId)
        : null;
    if (stationItem && stationItem.children) {
        const hasEquipmentData = stationItem.children.some(system =>
            system.children && system.children.length > 0
        );
        if (hasEquipmentData) {
            return;
        }
    }
    cascaderLoading.value = true;
    optionAPI.getEquipment(stationId).then(res => {
        const targetLine = cascaderOptions.value.find(line =>
            line.children && line.children.some(station => station.value === stationId)
        );
        if (targetLine) {
            const targetStation = targetLine.children.find(station => station.value === stationId);
            if (targetStation) {
                targetStation.children = res.data.tree.systemTree.map(system => ({
                    text: system.sysSystemName,
                    value: system.id,
                    children: system.equipmentTree.map(equipment => ({
                        text: equipment.name,
                        value: equipment.id,
                    })).sort((a, b) => a.text.localeCompare(b.text, undefined, {
                        numeric: true,
                        sensitivity: 'base'
                    }))
                })).sort((a, b) => a.text.localeCompare(b.text, undefined, {
                    numeric: true,
                    sensitivity: 'base'
                }));
            }
        }
        cascaderLoading.value = false;
    }).catch(error => {
        errorNotify("ChaXianHeTu.vue", "getEquipment", error);
        cascaderLoading.value = false;
    });
}
const onCascaderFinish = ({ selectedOptions }) => {
    const labels = selectedOptions.map(option => option.text);
    cxhtCacheKey.value = labels.join("_");
    title.value = cxhtCacheKey.value.split("_")[3]
    loadFromIDB()
};
const loadFromIDB = async () => {
    try {
        const cachedData = await db.cxhtCache.get(cxhtCacheKey.value);
        const getForm = async () => {
            showLoadingToast({
                message: '加载数据中',
                forbidClick: true
            });
            const formListRes = await formAPI.getFormByEquipmentId(cascaderValue.value);
            const formDetailRes = await formAPI.findListByFormIdForForm(formListRes.data.page.list[0].id);
            cxhtCacheData.value = formDetailRes.data.data;
            await db.cxhtCache.put({
                key: cxhtCacheKey.value,
                data: {
                    value: formDetailRes.data.data,
                    date: new Date().getTime()
                }
            });
            cascaderLoading.value = false;
            showCascaderPopup.value = false;
            closeToast()
        }
        if (cachedData && cachedData.data) {
            if (cachedData.data.date < new Date().getTime() - 24 * 60 * 60 * 1000) {
                getForm()
                return;
            }
            cascaderLoading.value = false;
            showCascaderPopup.value = false;
            cxhtCacheData.value = JSON.parse(JSON.stringify(cachedData.data.value));
        } else {
            getForm()
        }
    } catch (error) {
        errorNotify("ChaXianHeTu.vue", "loadFromIDB", error);
        showCascaderPopup.value = false;
    }
};
const actionSheetActions = [
    { name: '重置数据' },
    { name: '同步数据' }
];
const onActionSheetSelect = (action) => {
    if (action.name === '重置数据') {
        showConfirmDialog({
            title: '重置数据',
            message: '是否确认重置数据？该操作无法撤销。',
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            onConfirm: async () => {
                if (!cxhtCacheData.value) return;
                const newData = JSON.parse(JSON.stringify(cxhtCacheData.value));
                newData.forEach(item => {
                    if (typeof item === 'object' && item !== null) {
                        item.isRight = null;
                        item.remark = null;
                    }
                })
                cxhtCacheData.value = newData;
                activeNames.value = "";
                showActionSheet.value = false;
                await db.cxhtCache.put({
                    key: cxhtCacheKey.value,
                    data: {
                        value: newData,
                        date: new Date().getTime()
                    }
                });
                showSuccessToast('数据已重置');
            },
            onCancel: () => { }
        });
    } else if (action.name === '同步数据') {
        syncData();
    }
};
const syncData = async () => {
    if (!cxhtCacheData.value) {
        showToast('无数据可同步');
        return;
    }
    try {
        showLoadingToast({ message: '同步中...', forbidClick: true });
        await formAPI.syncData({
            key: cxhtCacheKey.value,
            data: cxhtCacheData.value
        });
        showToast('同步成功');
    } catch (error) {
        errorNotify("ChaXianHeTu.vue", "syncData", error);
    } finally {
        closeToast();
        showActionSheet.value = false;
    }
};
const keyGroups = computed(() => {
    if (!cxhtCacheData.value) return {};
    const groups = {};
    cxhtCacheData.value.forEach(item => {
        const loop = item.cxhtFormItem.startPart;
        if (!groups[loop]) {
            groups[loop] = [];
        }
        groups[loop].push(item);
    });
    return groups;
});
const sortedKeyGroups = computed(() => {
    const raw = keyGroups.value;
    const result = {};
    const keys = Object.keys(raw).sort(naturalSort);
    for (const key of keys) {
        let items = raw[key] || [];
        items = [...items].sort((a, b) =>
            naturalSort(
                a.cxhtFormItem.startNumber,
                b.cxhtFormItem.startNumber
            )
        );
        result[key] = items.map(item => ({ ...item }));
    }
    return result;
});
const filteredKeyGroups = computed(() => {
    if (!searchQuery.value) {
        return sortedKeyGroups.value;
    }
    const query = searchQuery.value.toLowerCase();
    window.scrollTo({ top: 0, behavior: 'smooth' });
    return Object.keys(sortedKeyGroups.value).reduce((acc, key) => {
        if (key.toLowerCase().includes(query)) {
            acc[key] = sortedKeyGroups.value[key];
        }
        return acc;
    }, {});
});
const progressPercentage = computed(() => {
    let total = 0;
    let completed = 0;
    Object.values(sortedKeyGroups.value).forEach(items => {
        total += items.length;
        completed += items.filter(item => item.isRight != null).length;
    });
    if (total === 0) return 0;
    return Math.round((completed / total) * 100);
});
const getProgressText = (items) => {
    const total = items.length;
    const completed = items.filter(item => item.isRight != null).length;
    if (total === 0 || completed === total) {
        return '已完成';
    } else {
        return `${completed} / ${total}`;
    }
};
const getProgressClass = (items) => {
    const total = items.length;
    const completed = items.filter(item => item.isRight !== null).length;
    if (total === 0 || completed === total) {
        return 'green';
    } else {
        return 'blue';
    }
};
const buttonClick = (item, key) => {
    currentKey.value = key;
    itemData.value = JSON.parse(JSON.stringify(item));
    showPopup.value = true;
};
const flatItems = computed(() => {
    const result = [];
    const keys = Object.keys(sortedKeyGroups.value).sort(naturalSort);
    for (const key of keys) {
        const items = sortedKeyGroups.value[key] || [];
        for (const item of items) {
            result.push({ key, ...item });
        }
    }
    return result;
});
const getCurrentIndex = () => {
    if (!itemData.value) return -1;
    return flatItems.value.findIndex(i => i.id === itemData.value.id);
};
const setResult = async (result) => {
    if (!itemData.value) return;
    await updateStoreData();
    const itemId = itemData.value.id;
    const originalItem = cxhtCacheData.value.find(item => item.id === itemId);
    if (originalItem) {
        originalItem.isRight = result;
        originalItem.remark = itemData.value.remark;
        await db.cxhtCache.put({
            key: cxhtCacheKey.value,
            data: {
                value: JSON.parse(JSON.stringify(cxhtCacheData.value)),
                date: new Date().getTime()
            }
        });
    }
    let nextIndex = getCurrentIndex() + 1;
    const allItems = flatItems.value;
    while (nextIndex < allItems.length) {
        const nextItem = allItems[nextIndex];
        const group = keyGroups.value[nextItem.key] || [];
        const storeItem = group.find(i => i.id === nextItem.id);
        if (storeItem && storeItem.isRight === null) {
            currentKey.value = nextItem.key;
            itemData.value = JSON.parse(JSON.stringify(storeItem));
            return;
        }
        nextIndex++;
    }
    showPopup.value = false;
};
const updateStoreData = async () => {
    if (!currentKey.value || !itemData.value) return;
    const keyGroup = keyGroups.value[currentKey.value];
    if (!keyGroup) return;
    const targetIndex = keyGroup.findIndex(item => item.id === itemData.value.id);
    if (targetIndex === -1) return;
    keyGroup[targetIndex].remark = itemData.value.remark;
    await db.cxhtCache.put({
        key: cxhtCacheKey.value,
        data: {
            value: JSON.parse(JSON.stringify(cxhtCacheData.value)),
            date: new Date().getTime()
        }
    });
};
const handleRemarkChange = async () => {
    await updateStoreData();
};
</script>
<style scoped>
.collapse-item-button {
    margin-bottom: 8px;
    text-align: left;
}

.van-popup {
    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
    width: 90%;
    overflow: hidden;
}

.dialog-content {
    padding: 24px;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.circuit-name {
    font-size: 18px;
    font-weight: 600;
    color: #333;
    padding-bottom: 8px;
    border-bottom: 1px solid #f0f0f0;
}

.startend-text {
    background-color: #ecf5ff;
    border-radius: 10px;
    padding: 12px 16px;
    font-size: 16px;
    font-weight: 500;
    color: #409eff;
    text-align: center;
    box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1);
    margin-bottom: 8px;
}

.correct-btn {
    background-color: #f0fbef !important;
    color: #67c23a !important;
}

.incorrect-btn {
    background-color: #fff0f0 !important;
    color: #ff4949 !important;
}

.van-field {
    border-radius: 8px;
    border: 1px solid #dcdfe6;
    background-color: #f5f7fa;
}

.van-field__control {
    padding: 12px;
}

.progress-text {
    margin-left: 8px;
    font-weight: normal;
    font-size: 14px;
}

.progress-text.green {
    color: #67c23a;
}

.progress-text.blue {
    color: #409eff;
}

.progress-text.gray {
    color: #909399;
}

.progress-container {
    padding: 16px;
    background-color: #ffffff;
    position: relative;
    display: block;
    align-items: center;
}

.dots-menu {
    font-size: 24px;
    padding: 0 10px;
    user-select: none;
}

.loading-container {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

.error-container {
    padding: 20px;
    text-align: center;
    color: #ff4949;
    margin-top: 20px;
}

.collapse-title {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
}
</style>
